﻿using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using MiniFox.Utility;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
using System.Reflection;

namespace MiniFox.Web
{
    /// <summary>
    /// 
    /// </summary>
    public static class HtmlExtensions
    {
        private static IDictionary<string, object> GetAttributeDictionary(object htmlAttributes)
        {
            IDictionary<string, object> htmlAttrs;
            if (htmlAttributes == null)
            {
                htmlAttrs = new Dictionary<string, object>();
            }
            else
            {
                htmlAttrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            }
            return htmlAttrs;
        }

        private static string GetHtmlAttributes(object htmlAttributes)
        {
            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);
            return GetHtmlAttributes(htmlAttrs);
        }

        private static string GetHtmlAttributes(IDictionary<string, object> htmlAttrbutes)
        {
            List<string> attrList = new List<string>();
            foreach (KeyValuePair<string, object> kv in htmlAttrbutes)
            {
                attrList.Add($"{kv.Key}=\"{kv.Value}\"");
            }
            return string.Join(" ", attrList.ToArray());
        }

        #region json
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static IHtmlContent Json(this IHtmlHelper html, object obj)
        {
            var htmlstr = JsonConvert.SerializeObject(obj);

            IHtmlContent htm = new HtmlString(htmlstr);

            return htm;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static IHtmlContent JsonFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
        {
            //Type mtype = typeof(TModel);
            //Type rtype = typeof(TValue);
            MemberExpression exp = expression.Body as MemberExpression;
            string htmlstr = "null";
            if (exp != null)
            {
                MemberInfo member = exp.Member;
                if (member != null && member.MemberType != MemberTypes.Property)
                    return new HtmlString(htmlstr);

                PropertyInfo property = member as PropertyInfo;
                if (property == null)
                    return new HtmlString(htmlstr);
            }

            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();

                object val = func(html.ViewData.Model);
                htmlstr = JsonConvert.SerializeObject(val);
            }
            HtmlString htm = new HtmlString(htmlstr);

            return htm;
        }
        #endregion

        #region checkbox
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static IHtmlContent CheckFor<TModel>(this IHtmlHelper<TModel> html, Expression<Func<TModel, bool>> expression)
        {
            return CheckFor(html, expression, null, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="disabled"></param>
        /// <returns></returns>
        public static IHtmlContent CheckFor<TModel>(this IHtmlHelper<TModel> html, Expression<Func<TModel, bool>> expression, object htmlAttributes, bool disabled)
        {
            MemberExpression exp = expression.Body as MemberExpression;
            ParameterExpression par = expression.Parameters[0];
            MemberInfo member = exp.Member;
            string htmlstr = string.Empty;
            if (member != null && member.MemberType != MemberTypes.Property)
                return new HtmlString(htmlstr);

            PropertyInfo property = member as PropertyInfo;
            if (property == null)
                return new HtmlString(htmlstr);
            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);
            bool val = false;
            if (html.ViewData.Model != null)
            {
                Func<TModel, bool> func = expression.Compile();
                val = func(html.ViewData.Model);
            }
            if (val)
            {
                if (htmlAttrs.ContainsKey("checked"))
                    htmlAttrs["checked"] = "checked";
                else
                    htmlAttrs.Add("checked", "checked");
            }
            if (htmlAttrs.ContainsKey("value"))
                htmlAttrs["value"] = "true";
            else
                htmlAttrs.Add("value", "true");

            if (disabled)
            {
                if (htmlAttrs.ContainsKey("disabled"))
                    htmlAttrs["disabled"] = "disabled";
                else
                    htmlAttrs.Add("disabled", "disabled");
            }

            string id = html.IdFor(expression);
            if (htmlAttrs.ContainsKey("id"))
                htmlAttrs["id"] = id;
            else
                htmlAttrs.Add("id", id);
            string name = html.NameFor(expression);
            if (htmlAttrs.ContainsKey("name"))
                htmlAttrs["name"] = name;
            else
                htmlAttrs.Add("name", name);

            if (htmlAttrs.ContainsKey("type"))
                htmlAttrs["type"] = "checkbox";
            else
                htmlAttrs.Add("type", "checkbox");

            if (htmlAttrs.ContainsKey("data-type"))
                htmlAttrs["data-type"] = "bool";
            else
                htmlAttrs.Add("data-type", "bool");


            htmlstr = "<input " + GetHtmlAttributes(htmlAttrs) + " />";
            HtmlString htm = new HtmlString(htmlstr);

            return htm;
        }
        #endregion

        #region datepicker
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public static IHtmlContent DatePicker(this IHtmlHelper html, string name, object val)
        {
            return DatePicker(html, name, val, null, false, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="val"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static IHtmlContent DatePicker(this IHtmlHelper html, string name, object val, object htmlAttributes)
        {
            return DatePicker(html, name, val, null, false, htmlAttributes);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="val"></param>
        /// <param name="showTime"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static IHtmlContent DatePicker(this IHtmlHelper html, string name, object val, bool showTime, object htmlAttributes)
        {
            return DatePicker(html, name, val, null, showTime, htmlAttributes);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="val"></param>
        /// <param name="format"></param>
        /// <param name="showTime"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static IHtmlContent DatePicker(this IHtmlHelper html, string name, object val, string format, bool showTime, object htmlAttributes)
        {
            var htmlAttrs = GetAttributeDictionary(htmlAttributes);

            if (showTime)
            {
                if (string.IsNullOrWhiteSpace(format))
                {
                    format = "{0:yyyy-MM-dd HH:mm:ss}";
                }
                if (htmlAttrs.ContainsKey("data-type"))
                {
                    htmlAttrs["data-type"] = "datetime";
                }
                else
                {
                    htmlAttrs.Add("data-type", "datetime");
                }
            }
            else
            {
                if (string.IsNullOrWhiteSpace(format))
                {
                    format = "{0:yyyy-MM-dd}";
                }
                if (htmlAttrs.ContainsKey("data-type"))
                {
                    htmlAttrs["data-type"] = "date";
                }
                else
                {
                    htmlAttrs.Add("data-type", "date");
                }
            }
            return html.TextBox(name, val, format, htmlAttrs);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static IHtmlContent DatePickerFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
        {
            return DatePickerFor(html, expression, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static IHtmlContent DatePickerFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
        {
            MemberExpression exp = expression.Body as MemberExpression;
            ParameterExpression par = expression.Parameters[0];
            MemberInfo member = exp.Member;
            string htmlstr = string.Empty;
            if (member != null && member.MemberType != MemberTypes.Property)
                return new HtmlString(htmlstr);

            PropertyInfo property = member as PropertyInfo;
            if (property == null)
                return new HtmlString(htmlstr);

            var datatypeAttr = Attribute.GetCustomAttribute(property, typeof(DataTypeAttribute)) as DataTypeAttribute;

            var htmlAttrs = GetAttributeDictionary(htmlAttributes);

            if (datatypeAttr != null && datatypeAttr.DataType == DataType.DateTime)
            {
                if (htmlAttrs.ContainsKey("data-type"))
                {
                    htmlAttrs["data-type"] = "datetime";
                }
                else
                {
                    htmlAttrs.Add("data-type", "datetime");
                }
            }
            else
            {
                if (htmlAttrs.ContainsKey("data-type"))
                {
                    htmlAttrs["data-type"] = "date";
                }
                else
                {
                    htmlAttrs.Add("data-type", "date");
                }
            }
            var formatAttr = Attribute.GetCustomAttribute(property, typeof(System.ComponentModel.DataAnnotations.DisplayFormatAttribute)) as System.ComponentModel.DataAnnotations.DisplayFormatAttribute;

            if (formatAttr != null)
            {
                return html.TextBoxFor(expression, formatAttr.DataFormatString, htmlAttrs);
            }
            else
            {
                return html.TextBoxFor(expression, htmlAttrs);
            }
        }
        #endregion

        #region lookup, autocomplete
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="val"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="listupUrl"></param>
        /// <param name="lookupUrl"></param>
        /// <param name="keyField"></param>
        /// <param name="textField"></param>
        /// <param name="sortField"></param>
        /// <param name="searchFields"></param>
        /// <returns></returns>
        public static IHtmlContent Lookup(this IHtmlHelper html, string name, object val, object htmlAttributes, string listupUrl, string lookupUrl, string keyField, string textField, string sortField, params string[] searchFields)
        {
            return Lookup(html, name, val, htmlAttributes, listupUrl, lookupUrl, new string[] { keyField }, textField, sortField, searchFields);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="val"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="listupUrl"></param>
        /// <param name="lookupUrl"></param>
        /// <param name="keyFields"></param>
        /// <param name="textField"></param>
        /// <param name="sortField"></param>
        /// <param name="searchFields"></param>
        /// <returns></returns>
        public static IHtmlContent Lookup(this IHtmlHelper html, string name, object val, object htmlAttributes, string listupUrl, string lookupUrl, string[] keyFields, string textField, string sortField, params string[] searchFields)
        {
            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);

            htmlAttrs.Add("data-type", "lookup");

            htmlAttrs.Add("keyField", string.Join(",", keyFields));
            htmlAttrs.Add("textField", textField);
            htmlAttrs.Add("sortField", sortField);
            htmlAttrs.Add("searchFields", string.Join(",", searchFields));
            htmlAttrs.Add("listupUrl", listupUrl);
            htmlAttrs.Add("lookupUrl", lookupUrl);

            return html.Hidden(name, val, htmlAttrs);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="listupUrl"></param>
        /// <param name="lookupUrl"></param>
        /// <param name="itemUrl"></param>
        /// <param name="keyField"></param>
        /// <param name="textField"></param>
        /// <param name="sortField"></param>
        /// <param name="searchFields"></param>
        /// <returns></returns>
        public static IHtmlContent LookupFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes, string listupUrl, string lookupUrl, string itemUrl, string keyField, string textField, string sortField, params string[] searchFields)
        {
            return LookupFor(html, expression, htmlAttributes, listupUrl, lookupUrl, itemUrl, new string[] { keyField }, textField, sortField, searchFields);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="listupUrl"></param>
        /// <param name="lookupUrl"></param>
        /// <param name="itemUrl"></param>
        /// <param name="keyFields"></param>
        /// <param name="textField"></param>
        /// <param name="sortField"></param>
        /// <param name="searchFields"></param>
        /// <returns></returns>
        public static IHtmlContent LookupFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes, string listupUrl, string lookupUrl, string itemUrl, string[] keyFields, string textField, string sortField, params string[] searchFields)
        {
            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);
            htmlAttrs.Add("data-type", "lookup");

            htmlAttrs.Add("keyField", string.Join(",", keyFields));
            htmlAttrs.Add("textField", textField);
            htmlAttrs.Add("sortField", sortField);
            htmlAttrs.Add("searchFields", string.Join(",", searchFields));
            htmlAttrs.Add("itemUrl", itemUrl);
            htmlAttrs.Add("listupUrl", listupUrl);
            htmlAttrs.Add("lookupUrl", lookupUrl);

            return html.HiddenFor(expression, htmlAttrs);
        }

        #endregion

        #region optionset

        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="enumType"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectList(this IHtmlHelper html, string name, Type enumType, string optionLabel = "")
        {
            return SelectList(html, name, null, enumType, null, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="enumType"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectList(this IHtmlHelper html, string name, Type enumType, object htmlAttributes, string optionLabel = "")
        {
            return SelectList(html, name, null, enumType, htmlAttributes, optionLabel);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="enumType"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectList(this IHtmlHelper html, string name, string value, Type enumType, string optionLabel = "")
        {
            return SelectList(html, name, value, enumType, null, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="enumType"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectList(this IHtmlHelper html, string name, string value, Type enumType, object htmlAttributes, string optionLabel = "")
        {
            List<SelectListItem> list = new List<SelectListItem>();
            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);

            var dict = enumType.ToDictionary();
            foreach (var kv in dict)
            {
                var val = kv.Key.ToString();
                list.Add(new SelectListItem { Text = kv.Value, Value = val, Selected = string.Equals(value, val) });
            }
            if (string.IsNullOrEmpty(optionLabel))
                return html.DropDownList(name, list, htmlAttrs);
            return html.DropDownList(name, list, optionLabel, htmlAttrs);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TList"></typeparam>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="optionList"></param>
        /// <param name="valField"></param>
        /// <param name="txtField"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectList<TList>(this IHtmlHelper html, string name, IEnumerable<TList> optionList, string valField, string txtField, string optionLabel = "")
        {
            return SelectList(html, name, null, optionList, valField, txtField, null, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TList"></typeparam>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="optionList"></param>
        /// <param name="valField"></param>
        /// <param name="txtField"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectList<TList>(this IHtmlHelper html, string name, string value, IEnumerable<TList> optionList, string valField, string txtField, string optionLabel = "")
        {
            return SelectList(html, name, value, optionList, valField, txtField, null, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TList"></typeparam>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="optionList"></param>
        /// <param name="valField"></param>
        /// <param name="txtField"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectList<TList>(this IHtmlHelper html, string name, string value, IEnumerable<TList> optionList, string valField, string txtField, object htmlAttributes, string optionLabel = "")
        {
            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);

            Type listType = typeof(TList);
            PropertyInfo valMember = listType.GetProperty(valField, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            PropertyInfo txtMember = listType.GetProperty(txtField, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);

            List<SelectListItem> list = new List<SelectListItem>();
            foreach (TList item in optionList)
            {
                object val = valMember.GetValue(item);
                object txt = txtMember.GetValue(item);
                list.Add(new SelectListItem { Text = txt.ToString(), Value = val.ToString(), Selected = (string.Equals(value, val)) });
            }
            if (string.IsNullOrEmpty(optionLabel))
                return html.DropDownList(name, list, htmlAttrs);
            return html.DropDownList(name, list, optionLabel, htmlAttrs);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string optionLabel = "")
        {
            return SelectListFor<TModel, TValue>(html, expression, null, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes, string optionLabel = "")
        {
            MemberExpression exp = expression.Body as MemberExpression;
            MemberInfo member = exp.Member;
            EnumDataTypeAttribute enumAtt = System.Attribute.GetCustomAttribute(member, typeof(EnumDataTypeAttribute)) as EnumDataTypeAttribute;
            if (enumAtt == null)
            {
                throw new InvalidOperationException();
            }

            return SelectListFor(html, expression, enumAtt.EnumType, htmlAttributes, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="enumType"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Type enumType, object htmlAttributes, string optionLabel = "")
        {
            return SelectListFor(html, expression, enumType, htmlAttributes, false, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="enumType"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="useNameAsValue"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Type enumType, object htmlAttributes, bool useNameAsValue, string optionLabel = "")
        {
            List<SelectListItem> list = new List<SelectListItem>();

            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);
            object value = null;
            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();
                value = func(html.ViewData.Model);
            }
            var dict = enumType.ToDictionary();
            foreach (var kv in dict)
            {
                var val = useNameAsValue ? kv.Value : kv.Key.ToString();
                list.Add(new SelectListItem { Text = kv.Value, Value = val, Selected = (value != null && string.Equals(value.ToString(), kv.Value, StringComparison.OrdinalIgnoreCase)) });
            }
            if (string.IsNullOrEmpty(optionLabel))
                return html.DropDownListFor(expression, list, htmlAttrs);
            return html.DropDownListFor(expression, list, optionLabel, htmlAttrs);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <typeparam name="TList"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="optionList"></param>
        /// <param name="valField"></param>
        /// <param name="txtField"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectListFor<TModel, TValue, TList>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IEnumerable<TList> optionList, string valField, string txtField, string optionLabel = "")
        {
            return SelectListFor(html, expression, optionList, valField, txtField, null, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <typeparam name="TList"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="optionList"></param>
        /// <param name="valField"></param>
        /// <param name="txtField"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent SelectListFor<TModel, TValue, TList>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IEnumerable<TList> optionList, string valField, string txtField, object htmlAttributes, string optionLabel = "")
        {

            object value = null;
            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();
                value = func(html.ViewData.Model);
            }
            Type listType = typeof(TList);
            PropertyInfo valMember = listType.GetProperty(valField, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            PropertyInfo txtMember = listType.GetProperty(txtField, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);

            List<SelectListItem> list = new List<SelectListItem>();
            foreach (TList item in optionList)
            {
                object val = valMember.GetValue(item);
                object txt = txtMember.GetValue(item);
                list.Add(new SelectListItem { Text = txt.ToString(), Value = val.ToString(), Selected = string.Equals(value, val) });
            }
            if (string.IsNullOrEmpty(optionLabel))
                return html.DropDownListFor(expression, list, htmlAttributes);
            return html.DropDownListFor(expression, list, optionLabel, htmlAttributes);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="dataUrl"></param>
        /// <param name="optionGroupName"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent OptionSetFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes, string dataUrl, string optionGroupName, string optionLabel = "")
        {
            MemberExpression exp = expression.Body as MemberExpression;
            MemberInfo member = exp.Member;
            object val = null;
            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();
                val = func(html.ViewData.Model);
            }

            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);

            htmlAttrs.Add("data-type", "options");
            htmlAttrs.Add("data-url", dataUrl);
            htmlAttrs.Add("optiongroup", optionGroupName);
            htmlAttrs.Add("optionvalue", val);
            return html.DropDownListFor(expression, null, optionLabel, htmlAttrs);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="dataUrl"></param>
        /// <param name="optionGroupName"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent OptionSet(this IHtmlHelper html, string name, string dataUrl, string optionGroupName, string optionLabel = "")
        {
            return OptionSet(html, name, string.Empty, dataUrl, optionGroupName, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="val"></param>
        /// <param name="dataUrl"></param>
        /// <param name="optionGroupName"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent OptionSet(this IHtmlHelper html, string name, string val, string dataUrl, string optionGroupName, string optionLabel = "")
        {
            return OptionSet(html, name, val, null, dataUrl, optionGroupName, optionLabel);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="htmlAttributes"></param>
        /// <param name="dataUrl"></param>
        /// <param name="optionGroupName"></param>
        /// <param name="val"></param>
        /// <param name="optionLabel"></param>
        /// <returns></returns>
        public static IHtmlContent OptionSet(this IHtmlHelper html, string name, string val, object htmlAttributes, string dataUrl, string optionGroupName, string optionLabel = "")
        {
            IDictionary<string, object> htmlAttrs = GetAttributeDictionary(htmlAttributes);
            htmlAttrs.Add("data-type", "options");
            htmlAttrs.Add("data-url", dataUrl);
            htmlAttrs.Add("optiongroup", optionGroupName);
            htmlAttrs.Add("optionvalue", val ?? string.Empty);
            return html.DropDownList(name, null, optionLabel, htmlAttrs);
        }
        #endregion

        #region radio list

        #region RadioButtonList dictionary
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, IDictionary<string, string> dictionary)
        {
            return RadioButtonList(html, name, dictionary, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="dictionary"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, IDictionary<string, string> dictionary, bool vertical)
        {
            return RadioButtonList(html, name, dictionary, vertical, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="dictionary"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, IDictionary<string, string> dictionary, bool vertical, object radioAttributes)
        {
            return RadioButtonList(html, name, null, dictionary, vertical, radioAttributes);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, string value, IDictionary<string, string> dictionary)
        {
            return RadioButtonList(html, name, value, dictionary, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="dictionary"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, string value, IDictionary<string, string> dictionary, bool vertical)
        {
            return RadioButtonList(html, name, value, dictionary, vertical, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="dictionary"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, string value, IDictionary<string, string> dictionary, bool vertical, object radioAttributes)
        {
            return RadioButtonList(html, name, value, dictionary, vertical, radioAttributes, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="dictionary"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="useNameAsValue"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, string value, IDictionary<string, string> dictionary, bool vertical, object radioAttributes, bool useNameAsValue)
        {

            string attrs = GetHtmlAttributes(radioAttributes);
            string labAttrs = vertical ? "radio" : "radio-inline";
            var dict = dictionary;

            List<string> list = new List<string>();
            foreach (var kv in dict)
            {
                var val = useNameAsValue ? kv.Value : kv.Key;

                string txt = kv.Value;
                string ischecked = (value != null && string.Equals(value, val, StringComparison.OrdinalIgnoreCase)) ? "checked" : string.Empty;
                string id = $"{name}-{val}";

                string str = $"<label class=\"{labAttrs}\"><input type=\"radio\" data-type=\"options\" name=\"{name}\" id=\"{id}\" value=\"{val}\" {ischecked} {attrs}/>{txt}</label>";
                list.Add(str);
            }
            string htmlstr = string.Join("", list.ToArray());

            IHtmlContent htm = new HtmlString(htmlstr);

            return htm;
        }
        #endregion

        #region RadioButtonList enumType

        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="enumType"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, Type enumType)
        {
            return RadioButtonList(html, name, null, enumType, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="enumType"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, Type enumType, bool vertical)
        {
            return RadioButtonList(html, name, null, enumType, vertical);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="enumType"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, string value, Type enumType)
        {
            return RadioButtonList(html, name, value, enumType, false, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="enumType"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, string value, Type enumType, bool vertical)
        {
            return RadioButtonList(html, name, value, enumType, vertical, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="enumType"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, string value, Type enumType, bool vertical, object radioAttributes)
        {
            return RadioButtonList(html, name, value, enumType, vertical, radioAttributes, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="enumType"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="useNameAsValue"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonList(this IHtmlHelper html, string name, string value, Type enumType, bool vertical, object radioAttributes, bool useNameAsValue)
        {

            string attrs = GetHtmlAttributes(radioAttributes);
            string labAttrs = vertical ? "radio" : "radio-inline";
            var dict = enumType.ToDictionary();

            List<string> list = new List<string>();
            foreach (var kv in dict)
            {
                var val = useNameAsValue ? kv.Value : kv.Key.ToString();

                object txt = kv.Value;
                string ischecked = (value != null && string.Equals(value.ToString(), kv.Value, StringComparison.OrdinalIgnoreCase)) ? "checked" : string.Empty;
                string id = name + "-" + val;
                string str = $"<label class=\"{labAttrs}\"><input type=\"radio\" data-type=\"options\" name=\"{name}\" id=\"{id}\" value=\"{val}\" {ischecked} {attrs}/>{txt}</label>";

                list.Add(str);
            }
            string htmlstr = string.Join("", list.ToArray());

            IHtmlContent htm = new HtmlString(htmlstr);

            return htm;
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, string> dictionary)
        {
            return RadioButtonListFor(html, expression, dictionary, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="dictionary"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, string> dictionary, bool vertical)
        {
            return RadioButtonListFor(html, expression, dictionary, vertical, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="dictionary"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, string> dictionary, bool vertical, object radioAttributes)
        {
            return RadioButtonListFor(html, expression, dictionary, vertical, radioAttributes, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="dictionary"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="useNameAsValue"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, string> dictionary, bool vertical, object radioAttributes, bool useNameAsValue)
        {
            MemberExpression exp = expression.Body as MemberExpression;
            if (exp == null)
            {
                return null;
            }

            MemberInfo member = exp.Member;
            if (member == null || member.MemberType != MemberTypes.Property)
            {
                return null;
            }

            PropertyInfo property = member as PropertyInfo;


            object value = null;
            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();
                value = func(html.ViewData.Model);
            }


            string attrs = GetHtmlAttributes(radioAttributes);
            string labAttrs = vertical ? "radio" : "radio-inline";
            var dict = dictionary;

            List<string> list = new List<string>();
            foreach (var kv in dict)
            {
                var val = useNameAsValue ? kv.Value : kv.Key;

                object txt = kv.Value;
                string ischecked = (value != null && string.Equals(value.ToString(), val, StringComparison.OrdinalIgnoreCase)) ? "checked" : string.Empty;
                string id = property.Name + "-" + val;
                string str = "<label class=\"" + labAttrs + "\">" +
                    "<input type=\"radio\" data-type=\"options\" name=\"" + property.Name + "\" id=\"" + id + "\" value=\"" + val + "\" " + ischecked + " " + attrs + "/>" + txt +
                    "</label>";
                list.Add(str);
            }
            string htmlstr = string.Join("", list.ToArray());

            IHtmlContent htm = new HtmlString(htmlstr);

            return htm;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
        {
            return RadioButtonListFor(html, expression, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, bool vertical)
        {
            return RadioButtonListFor(html, expression, vertical, null, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, bool vertical, object radioAttributes)
        {
            return RadioButtonListFor(html, expression, vertical, radioAttributes, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="useNameAsValue"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, bool vertical, object radioAttributes, bool useNameAsValue)
        {
            MemberExpression exp = expression.Body as MemberExpression;
            MemberInfo member = exp.Member;
            EnumDataTypeAttribute enumAtt = System.Attribute.GetCustomAttribute(member, typeof(EnumDataTypeAttribute)) as EnumDataTypeAttribute;
            if (enumAtt == null)
            {
                throw new InvalidOperationException();
            }

            return RadioButtonListFor(html, expression, enumAtt.EnumType, vertical, radioAttributes, useNameAsValue);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="enumType"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Type enumType)
        {
            return RadioButtonListFor(html, expression, enumType, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="enumType"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Type enumType, bool vertical)
        {
            return RadioButtonListFor(html, expression, enumType, vertical, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="enumType"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Type enumType, bool vertical, object radioAttributes)
        {
            return RadioButtonListFor(html, expression, enumType, vertical, radioAttributes, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="enumType"></param>
        /// <param name="radioAttributes"></param>
        /// <param name="useNameAsValue"></param>
        /// <param name="vertical"></param>
        /// <returns></returns>
        public static IHtmlContent RadioButtonListFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Type enumType, bool vertical, object radioAttributes, bool useNameAsValue)
        {
            MemberExpression exp = expression.Body as MemberExpression;
            if (exp == null)
            {
                return null;
            }

            MemberInfo member = exp.Member;
            if (member == null || member.MemberType != MemberTypes.Property)
            {
                return null;
            }

            PropertyInfo property = member as PropertyInfo;


            object value = null;
            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();
                value = func(html.ViewData.Model);
            }


            string attrs = GetHtmlAttributes(radioAttributes);
            string labAttrs = vertical ? "radio" : "radio-inline";
            var dict = enumType.ToDictionary();

            List<string> list = new List<string>();
            foreach (var kv in dict)
            {
                var val = useNameAsValue ? kv.Value : kv.Key.ToString();

                object txt = kv.Value;
                string ischecked = (value != null && string.Equals(value.ToString(), kv.Value, StringComparison.OrdinalIgnoreCase)) ? "checked" : string.Empty;
                string id = property.Name + "-" + val;
                string str = "<label class=\"" + labAttrs + "\">" +
                    "<input type=\"radio\" data-type=\"options\" name=\"" + property.Name + "\" id=\"" + id + "\" value=\"" + val + "\" " + ischecked + " " + attrs + "/>" + txt +
                    "</label>";
                list.Add(str);
            }
            string htmlstr = string.Join("", list.ToArray());

            HtmlString htm = new HtmlString(htmlstr);

            return htm;
        }
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <typeparam name="TModel"></typeparam>
        ///// <typeparam name="TValue"></typeparam>
        ///// <typeparam name="TOption"></typeparam>
        ///// <param name="html"></param>
        ///// <param name="expression"></param>
        ///// <param name="optionList"></param>
        ///// <param name="valField"></param>
        ///// <param name="txtField"></param>
        ///// <returns></returns>
        //public static HtmlString RadioButtonListFor<TModel, TValue, TOption>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IEnumerable<TOption> optionList, string valField, string txtField)
        //{
        //    return RadioButtonListFor(html, expression, optionList, valField, txtField, null, false);
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <typeparam name="TModel"></typeparam>
        ///// <typeparam name="TValue"></typeparam>
        ///// <typeparam name="TOption"></typeparam>
        ///// <param name="html"></param>
        ///// <param name="expression"></param>
        ///// <param name="optionList"></param>
        ///// <param name="valField"></param>
        ///// <param name="txtField"></param>
        ///// <param name="vertical"></param>
        ///// <returns></returns>
        //public static HtmlString RadioButtonListFor<TModel, TValue, TOption>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IEnumerable<TOption> optionList, string valField, string txtField, bool vertical)
        //{
        //    return RadioButtonListFor(html, expression, optionList, valField, txtField, null, vertical);
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <typeparam name="TModel"></typeparam>
        ///// <typeparam name="TValue"></typeparam>
        ///// <typeparam name="TOption"></typeparam>
        ///// <param name="html"></param>
        ///// <param name="expression"></param>
        ///// <param name="optionList"></param>
        ///// <param name="valField"></param>
        ///// <param name="txtField"></param>
        ///// <param name="radioAttributes"></param>
        ///// <param name="vertical"></param>
        ///// <returns></returns>
        //public static HtmlString RadioButtonListFor<TModel, TValue, TOption>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IEnumerable<TOption> optionList, string valField, string txtField, object radioAttributes, bool vertical)
        //{
        //    MemberExpression exp = expression.Body as MemberExpression;
        //    if (exp == null)
        //    {
        //        return null;
        //    }

        //    MemberInfo member = exp.Member;
        //    if (member == null || member.MemberType != MemberTypes.Property)
        //    {
        //        return null;
        //    }

        //    PropertyInfo property = member as PropertyInfo;


        //    object value = null;
        //    if (html.ViewData.Model != null)
        //    {
        //        Func<TModel, TValue> func = expression.Compile();
        //        value = func(html.ViewData.Model);
        //    }


        //    string attrs = GetHtmlAttributes(radioAttributes);
        //    string labAttrs = vertical ? "radio" : "radio-inline";
        //    Type listType = typeof(TOption);
        //    PropertyInfo valMember = listType.GetProperty(valField, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
        //    PropertyInfo txtMember = listType.GetProperty(txtField, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);

        //    List<string> list = new List<string>();
        //    foreach (TOption item in optionList)
        //    {
        //        var val = (string)valMember.GetValue(item, null);
        //        object txt = txtMember.GetValue(item, null);
        //        string ischecked = (value != null && string.Equals(value.ToString(), val, StringComparison.OrdinalIgnoreCase)) ? "checked" : string.Empty;
        //        string id = property.Name + "-" + val;
        //        string str = "<label class=\""+ labAttrs + "\">" +
        //            "<input type=\"radio\" name=\"" + property.Name + "\" id=\"" + id + "\" value=\"" + val + "\" " + ischecked + " " + attrs + "/>" + txt +
        //            "</label>";
        //        list.Add(str);
        //    }

        //    string htmlstr = string.Join("", list.ToArray());

        //    HtmlString htm = new HtmlString(htmlstr);

        //    return htm;
        //}
        #endregion

        #region description
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static IHtmlContent DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
        {
            return DescriptionFor(html, expression, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static IHtmlContent DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
        {
            MemberExpression exp = expression.Body as MemberExpression;
            ParameterExpression par = expression.Parameters[0];
            MemberInfo member = exp.Member;
            string txt = string.Empty;
            if (member == null || member.MemberType != MemberTypes.Property)
                return Description(html, txt, null);

            PropertyInfo property = member as PropertyInfo;

            var displayAttr = Attribute.GetCustomAttribute(property, typeof(DisplayAttribute)) as DisplayAttribute;
            txt = displayAttr.Description;

            return Description(html, txt, htmlAttributes);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="txt"></param>
        /// <returns></returns>
        public static IHtmlContent Description(this IHtmlHelper html, string txt)
        {
            return Description(html, txt, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="txt"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static IHtmlContent Description(this IHtmlHelper html, string txt, object htmlAttributes)
        {
            string attrs = GetHtmlAttributes(htmlAttributes);
            string htmlstr;
            if (string.IsNullOrWhiteSpace(attrs))
            {
                htmlstr = "<span>{0}</span>";
            }
            else
            {
                htmlstr = "<span " + attrs + ">{0}</span>";
            }
            htmlstr = string.Format(htmlstr, txt);

            HtmlString htm = new HtmlString(htmlstr);

            return htm;
        }
        #endregion
    }

}
